package org.example.builder;

import com.sun.org.apache.bcel.internal.generic.BALOAD;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.text.StrBuilder;
import org.example.bean.Constants;
import org.example.bean.FiledInfo;
import org.example.bean.TableInfo;
import org.example.utils.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class BuildMapperXML {
    private static Logger logger = LoggerFactory.getLogger(BuildMapperXML.class);
    private static final   String BASE_COLUMN_LIST = "base_column_list";
    private static final   String BASE_RESULT_MAP = "base_result_map";
    private static final   String BASE_QUERY_CONDITION = "base_query_condition";
    private static final   String BASE_QUERY_CONDITION_EXTEND = "base_query_condition_extend";
    private static final   String QUERY_CONDITION = "query_condition";
    public static void execute(TableInfo tableInfo) {
        File folder = new File(Constants.PATH_MAPPER_XML);

        if (!folder.exists()) {
            folder.mkdirs();
        }

        String className = tableInfo.getBeanName() + Constants.SUFFIX_MAPPER;
        File poFlie = new File(folder,className+ ".xml ");
        OutputStream out = null;
        OutputStreamWriter outw = null;
        BufferedWriter bw = null;
        try {

            out = new FileOutputStream(poFlie);
            outw = new OutputStreamWriter(out,"utf8");
            bw = new BufferedWriter(outw);


            String packageMapperXml = Constants.PACKAGE_MAPPER+ "."+className;

            bw.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
            bw.newLine();
            bw.write("<!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\" \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\n");
            bw.newLine();
            bw.write("<mapper namespace=\""+ packageMapperXml+"\">");
            bw.newLine();




            //通用查询映射resultMap
            bw.write("\t<!-- "+"通用查询映射resultMap"+" -->");
            bw.newLine();
            bw.write("\t<resultMap id=\""+BASE_RESULT_MAP+"\" type=\""+ Constants.PACKAGE_PO+"." +tableInfo.getBeanName() +"\">");
            bw.newLine();
            List<FiledInfo> primaryKeyList = tableInfo.getKeyIndexMap().get("PRIMARY");
            for (FiledInfo filedInfo : tableInfo.getFiledList()) {
                bw.write("\t\t<!-- "+filedInfo.getComment()+" -->");
                bw.newLine();
                if (primaryKeyList.size() == 1 && filedInfo.getFileName().equals(primaryKeyList.get(0).getFileName())) {
                    bw.write("\t\t <id column=\""+primaryKeyList.get(0).getFileName() +"\" property=\""+ primaryKeyList.get(0).getPropertyName()+"\" />");
                } else {
                    bw.write("\t\t <result column=\""+ filedInfo.getFileName()+"\" property=\""+ filedInfo.getPropertyName()+"\" />");
                }
                bw.newLine();
            }
            bw.write("\t</resultMap>");
            bw.newLine();
            bw.newLine();

            //通用查询结果列列
            bw.write("\t<!-- "+"通用查询结果列列"+" -->");
            bw.newLine();

            bw.write("\t<sql id=\"" + BASE_COLUMN_LIST + "\">");
            bw.newLine();
            StringBuilder columnBuilder = new StringBuilder();
            for (FiledInfo filedInfo : tableInfo.getFiledList()) {
                columnBuilder.append(filedInfo.getFileName()).append(",");
            }
            bw.write("\t\t"+columnBuilder.substring(0,columnBuilder.lastIndexOf(",")).toString());
            bw.newLine();
            bw.write("\t</sql>");
            bw.newLine();
            bw.newLine();

            //基础查询条件
            bw.write("\t<!-- "+"基础查询条件"+" -->");
            bw.newLine();
            bw.write("\t<sql id=\"" + BASE_QUERY_CONDITION + "\">");
            bw.newLine();

            for (FiledInfo filedInfo : tableInfo.getFiledList()) {

                String stringQuery = "";
                if(ArrayUtils.contains(Constants.SQL_STRING_TYPE,filedInfo.getSqlType())) {
                    stringQuery = " and query." + filedInfo.getPropertyName() +" != ''";
                }
                bw.write("\t\t<if test=\"query."+filedInfo.getPropertyName()+" != null"+stringQuery+"\">");
                bw.newLine();
                bw.write("\t\t\tand "+filedInfo.getPropertyName()+" = #{query." + filedInfo.getPropertyName()+"}");
                bw.newLine();
                bw.write("\t\t</if>");
                bw.newLine();
            }
            bw.newLine();
            bw.write("\t</sql>");
            bw.newLine();
            bw.newLine();



            //扩展的查询条件
            bw.write("\t<!-- "+"扩展的查询条件"+" -->");
            bw.newLine();
            bw.write("\t<sql id=\"" + BASE_QUERY_CONDITION_EXTEND + "\">");

            bw.newLine();
            for (FiledInfo filedInfo : tableInfo.getFiledExtendsList()) {
                String stringQuery =  " and query." + filedInfo.getPropertyName() +" != ''";;
                String stringCondition = "";
                if(ArrayUtils.contains(Constants.SQL_STRING_TYPE,filedInfo.getSqlType())) {
                    stringCondition = "and " + filedInfo.getFileName() +" like concat('%', #{query."+filedInfo.getPropertyName()+"}, '%')";

                } else if (ArrayUtils.contains(Constants.SQL_DATE_TYPES,filedInfo.getSqlType()) ||
                        ArrayUtils.contains(Constants.SQL_DATE_TIME_TYPES,filedInfo.getSqlType())) {

                    String dateType = "";
                    if (filedInfo.getPropertyName().endsWith(Constants.SUFFIX_BEAN_QUERY_TIME_START)) {
                        dateType = " >= str_to_date(#{query.";
                        stringCondition = "<![CDATA[ and " + filedInfo.getFileName()+dateType + filedInfo.getPropertyName()+"}, '%Y-%m-%d') ]]>";
                    } else if (filedInfo.getPropertyName().endsWith(Constants.SUFFIX_BEAN_QUERY_TIME_END)) {
                        dateType = " < date_sub(str_to_date(#{query.";
                        stringCondition = "<![CDATA[ and " + filedInfo.getFileName()+dateType + filedInfo.getPropertyName()+"}, '%Y-%m-%d'),interval -1 day) ]]>";
                    }

                }
                bw.write("\t\t<if test=\"query."+filedInfo.getPropertyName()+" != null"+stringQuery+"\">");
                bw.newLine();
                bw.write("\t\t\t"+stringCondition);
                bw.newLine();
                bw.write("\t\t</if>");
                bw.newLine();
            }
            bw.newLine();

            bw.write("\t</sql>");

            bw.newLine();
            bw.newLine();

            //通用查询条件
            bw.write("\t<!-- "+"通用查询条件"+" -->");
            bw.newLine();
            bw.write("\t<sql id=\"" + QUERY_CONDITION + "\">");
            bw.newLine();
            bw.write("\t\t<where>");
            bw.newLine();
            bw.write("\t\t\t<include refid=\"" + BASE_QUERY_CONDITION+"\"/>");
            bw.newLine();
            bw.write("\t\t\t<include refid=\"" + BASE_QUERY_CONDITION_EXTEND+"\"/>");
            bw.newLine();
            bw.write("\t\t</where>");
            bw.newLine();
            bw.write("\t</sql>");
            bw.newLine();
            bw.newLine();


            //查询集合
            bw.write("\t<!-- "+"查询列表 "+" -->");
            bw.newLine();
            bw.write("\t<select id=\"selectList\" resultMap=\""+BASE_RESULT_MAP+"\">");
            bw.newLine();
            bw.write("\t\tSELECT");
            bw.newLine();
            bw.write("\t\t<include refid=\""+BASE_COLUMN_LIST+"\"/>");
            bw.newLine();
            bw.write("\t\tFROM " + tableInfo.getTableName());
            bw.newLine();
            bw.write("\t\t<include refid=\""+QUERY_CONDITION+"\"/>");
            bw.newLine();
            bw.write("\t\t<if test=\"query.orderBy != null\">");
            bw.newLine();
            bw.write("\t\t\torder by ${query.orderBy}");
            bw.newLine();
            bw.write("\t\t</if>");
            bw.newLine();
            bw.write("\t\t<if test=\"query.simplePage != null\">");
            bw.newLine();
            bw.write("\t\t\tlimit #{query.simplePage.start},#{query.simplePage.end}");
            bw.newLine();
            bw.write("\t\t</if>");
            bw.newLine();
            bw.write("\t</select>");
            bw.newLine();
            bw.newLine();


            //查询数量
            bw.write("\t<!-- "+"查询数量 "+" -->");
            bw.newLine();
            bw.write("\t<select id=\"selectCount\" resultType=\"java.lang.Integer\">");
            bw.newLine();
            bw.write("\t\tSELECT count(1) FROM " + tableInfo.getTableName());
            bw.newLine();
            bw.write("\t\t<include refid=\""+QUERY_CONDITION+"\"/>");
            bw.newLine();
            bw.write("\t</select>");
            bw.newLine();
            bw.newLine();


            //单条插入
            bw.write("\t<!-- "+"插入 （匹配有值的字段）"+" -->");
            bw.newLine();
            bw.write("\t<insert id=\"insert\" parameterType=\""+Constants.PACKAGE_PO+"." +tableInfo.getBeanName()  +"\">");
            bw.newLine();
            //拿到自增长id
            FiledInfo autoIncrementField = null;
            for (FiledInfo filedInfo : tableInfo.getFiledList()) {
                if (filedInfo.getAutoIncrement() != null && filedInfo.getAutoIncrement() ) {
                    autoIncrementField = filedInfo;
                    break;
                }
            }
            if (autoIncrementField != null) {
                bw.newLine();
                bw.write("\t\t<selectKey keyProperty=\"bean.id\" resultType=\"Integer\" order=\"AFTER\">");
                bw.newLine();
                bw.write("\t\t\tSELECT LAST_INSERT_ID()");
                bw.newLine();
                bw.write("\t\t</selectKey>");
            }
            bw.newLine();
            bw.write("\t\tINSERT INTO "+ tableInfo.getTableName());
            bw.newLine();
            bw.write("\t\t<trim prefix=\"(\" suffix=\")\" suffixOverrides=\",\">");
            bw.newLine();
            for (FiledInfo filedInfo : tableInfo.getFiledList()) {
                bw.write("\t\t\t<if test=\"bean."+filedInfo.getPropertyName()+" != null\" >");
                bw.newLine();
                bw.write("\t\t\t\t"+filedInfo.getFileName()+",");
                bw.newLine();
                bw.write("\t\t\t</if>");
                bw.newLine();
            }
            bw.write("\t\t</trim>");
            bw.newLine();
            bw.write("\t\t<trim prefix=\"values (\" suffix=\")\" suffixOverrides=\",\">");
            bw.newLine();
            for (FiledInfo filedInfo : tableInfo.getFiledList()) {
                bw.write("\t\t\t<if test=\"bean."+filedInfo.getPropertyName()+" != null\">");
                bw.newLine();
                bw.write("\t\t\t\t#{bean."+filedInfo.getPropertyName()+"},");
                bw.newLine();
                bw.write("\t\t\t</if>");
                bw.newLine();
            }
            bw.write("\t\t</trim>");
            bw.newLine();
            bw.write("\t</insert>");
            bw.newLine();
            bw.newLine();


            //插入或者更新 （匹配有值的字段）
            bw.write("\t<!-- "+"插入或者更新 （匹配有值的字段）"+" -->");
            bw.newLine();
            bw.write("\t<insert id=\"insertOrUpdate\" parameterType=\""+Constants.PACKAGE_PO+"." +tableInfo.getBeanName()  +"\">");
            bw.newLine();
            bw.newLine();
            bw.write("\t\tINSERT INTO "+ tableInfo.getTableName());
            bw.newLine();
            bw.write("\t\t<trim prefix=\"(\" suffix=\")\" suffixOverrides=\",\">");
            bw.newLine();
            for (FiledInfo filedInfo : tableInfo.getFiledList()) {
                bw.write("\t\t\t<if test=\"bean."+filedInfo.getPropertyName()+" != null\">");
                bw.newLine();
                bw.write("\t\t\t\t"+filedInfo.getFileName()+",");
                bw.newLine();
                bw.write("\t\t\t</if>");
                bw.newLine();
            }
            bw.write("\t\t</trim>");
            bw.newLine();
            bw.write("\t\t<trim prefix=\"values (\" suffix=\")\" suffixOverrides=\",\">");
            bw.newLine();
            for (FiledInfo filedInfo : tableInfo.getFiledList()) {
                bw.write("\t\t\t<if test=\"bean."+filedInfo.getPropertyName()+" != null\">");
                bw.newLine();
                bw.write("\t\t\t\t#{bean."+filedInfo.getPropertyName()+"},");
                bw.newLine();
                bw.write("\t\t\t</if>");
                bw.newLine();
            }
            bw.write("\t\t</trim>");
            bw.newLine();
            bw.write("\t\ton DUPLICATE key update");
            bw.newLine();
            Map<String,String> keyTempMap = new HashMap<>();
            Map<String,List<FiledInfo>> keyIndexMap = tableInfo.getKeyIndexMap();
            for (Map.Entry<String ,List<FiledInfo>> entry : keyIndexMap.entrySet()) {
                List<FiledInfo> filedInfoList = entry.getValue();
                for (FiledInfo item : filedInfoList) {
                    keyTempMap.put(item.getFileName(),item.getFileName());
                }
            }
            bw.newLine();
            bw.write("\t\t<trim prefix=\"\" suffix=\"\" suffixOverrides=\",\">");
            bw.newLine();
            for (FiledInfo filedInfo : tableInfo.getFiledList()) {
                if(keyTempMap.get(filedInfo.getFileName()) != null) {
                    continue;
                }
                bw.write("\t\t\t<if test=\"bean."+filedInfo.getPropertyName()+" != null\">");
                bw.newLine();
                bw.write("\t\t\t\t"+filedInfo.getFileName()+" = VALUES("+ filedInfo.getFileName()+"),");
                bw.newLine();
                bw.write("\t\t\t</if>");
                bw.newLine();
            }
            bw.write("\t\t</trim>");
            bw.newLine();
            bw.write("\t</insert>");
            bw.newLine();
            bw.newLine();

            // 添加 （批量插入）
            bw.write("\t<!-- "+"添加 （批量插入）"+" -->");
            bw.newLine();
            bw.write("\t<insert id=\"insertBatch\" parameterType=\""+Constants.PACKAGE_PO+"." +tableInfo.getBeanName()  +"\">");
            bw.newLine();
            for (Map.Entry<String ,List<FiledInfo>> entry : keyIndexMap.entrySet()) {
                List<FiledInfo> filedInfoList = entry.getValue();
                for (FiledInfo item : filedInfoList) {
                    keyTempMap.put(item.getFileName(),item.getFileName());
                }
            }
            StringBuilder tempStr = new StringBuilder();
            StringBuilder tempStrPro = new StringBuilder();
            for (FiledInfo filedInfo : tableInfo.getFiledList()) {
                if(filedInfo.getAutoIncrement()) {
                    continue;
                }
                tempStr.append(filedInfo.getFileName() + ",");
                tempStrPro.append("#{item." + filedInfo.getPropertyName()+"},");
            }
            bw.write("\t\tINSERT INTO " + tableInfo.getTableName()+"(" +tempStr.substring(0,tempStr.length()-1)+ ")values");
            bw.newLine();
            bw.write("\t\t<foreach collection=\"list\" item=\"item\" separator=\",\">");
            bw.newLine();
            bw.write("\t\t\t(");
            bw.newLine();
            bw.write("\t\t\t" + tempStrPro.substring(0,tempStrPro.length()-1));
            bw.newLine();
            bw.write("\t\t\t)");
            bw.newLine();
            bw.write("\t\t</foreach>");
            bw.newLine();

            bw.write("\t</insert>");
            bw.newLine();
            bw.newLine();

            // 批量新增修改 （批量插入）
            bw.write("\t<!-- "+"批量新增修改 （批量插入）"+" -->");
            bw.newLine();
            bw.write("\t<insert id=\"insertOrUpdateBatch\" parameterType=\""+Constants.PACKAGE_PO+"." +tableInfo.getBeanName()  +"\">");
            bw.newLine();
            for (Map.Entry<String ,List<FiledInfo>> entry : keyIndexMap.entrySet()) {
                List<FiledInfo> filedInfoList = entry.getValue();
                for (FiledInfo item : filedInfoList) {
                    keyTempMap.put(item.getFileName(),item.getFileName());
                }
            }
            bw.write("\t\tINSERT INTO " + tableInfo.getTableName()+"(" +tempStr.substring(0,tempStr.length()-1)+ ")values");
            bw.newLine();
            bw.write("\t\t<foreach collection=\"list\" item=\"item\" separator=\",\">");
            bw.newLine();
            bw.write("\t\t\t(");
            bw.newLine();
            bw.write("\t\t\t" + tempStrPro.substring(0,tempStrPro.length()-1));
            bw.newLine();
            bw.write("\t\t\t)");
            bw.newLine();
            bw.write("\t\t</foreach>");
            bw.newLine();
            bw.write("\t\ton DUPLICATE key update");
            bw.newLine();
            StringBuilder tempBu = new StringBuilder();
            for (FiledInfo filedInfo : tableInfo.getFiledList()) {
                if(filedInfo.getAutoIncrement()) {
                    continue;
                }
                tempBu.append(filedInfo.getFileName() + " = VALUES(" + filedInfo.getFileName()+"),");


            }
            bw.write("\t\t"+ tempBu.substring(0,tempBu.lastIndexOf(",")));
            bw.newLine();
            bw.write("\t</insert>");
            bw.newLine();
            bw.newLine();


            //根据主键更新
            for ( Map.Entry<String, List<FiledInfo>> entry: keyIndexMap.entrySet()) {

                List<FiledInfo> keyFieldIndexList = entry.getValue();
                Integer index = 0;
                StringBuilder methodName = new StringBuilder();
                StringBuilder methodFieldName = new StringBuilder();
                StringBuilder paramsNames = new StringBuilder();
                for (FiledInfo filedInfo: keyFieldIndexList) {
                    index++;
                    methodName.append(StringUtils.upperCaseFirstLetter(filedInfo.getPropertyName()));
                    methodFieldName.append(filedInfo.getFileName());
                    paramsNames.append(filedInfo.getFileName()+"=#{" +filedInfo.getPropertyName() +"}");
                    if(index < keyFieldIndexList.size()) {
                        methodName.append("And");
                        paramsNames.append(" and ");
                    }

                }
                //查询
                //BuildComment.createFieldComment(bw,"根据" + methodName+"查询");
                bw.write("\t<!-- 根据"+methodName+"查询 -->");
                bw.newLine();
                bw.write("\t<select id=\"selectBy" + methodName + "\" resultMap=\""+BASE_RESULT_MAP+"\">");
                bw.newLine();
                bw.write("\t\tselect");
                bw.newLine();
                bw.write("\t\t<include refid=\"" + BASE_COLUMN_LIST +"\"/>");
                bw.newLine();
                bw.write("\t\tfrom " + tableInfo.getTableName() + " where " + paramsNames);
                bw.newLine();
                bw.write("\t</select>");
                bw.newLine();
                bw.newLine();



                //删除
                bw.write("\t<!-- 根据"+methodName+"删除 -->");
                bw.newLine();
                bw.write("\t<delete id=\"deleteBy" + methodName + "\">");
                bw.newLine();
                bw.write("\t\tdelete from " + tableInfo.getTableName() + " where " + paramsNames);
                bw.newLine();
                bw.write("\t</delete>");
                bw.newLine();
                bw.newLine();

                // 更新
                bw.write("\t<!-- 根据"+methodName+"更新 -->");
                bw.newLine();
                bw.write("\t<update id=\"updateBy" + methodName+ "\" parameterType=\""+Constants.PACKAGE_PO+"." +tableInfo.getBeanName()  +"\">");
                bw.newLine();
                bw.write("\t\tUPDATE " + tableInfo.getTableName());
                bw.newLine();
                bw.write("\t\t<set>");
                bw.newLine();
                for (FiledInfo filedInfo : tableInfo.getFiledList()) {
                    if(keyTempMap.get(filedInfo.getFileName()) != null) {
                        continue;
                    }
                    bw.write("\t\t\t<if test=\"bean."+filedInfo.getPropertyName()+" != null\">");
                    bw.newLine();
                    bw.write("\t\t\t\t"+filedInfo.getFileName()+" = #{bean."+ filedInfo.getPropertyName()+"},");
                    bw.newLine();
                    bw.write("\t\t\t</if>");
                    bw.newLine();
                }
                bw.write("\t\t</set>");
                bw.newLine();
                bw.write("\t\twhere "+methodFieldName+" = #{"+methodFieldName+"}");
                bw.newLine();
                bw.write("\t</update>");
                bw.newLine();
                bw.newLine();
            }







            bw.newLine();
            bw.write("</mapper>");
            bw.newLine();
            bw.newLine();
            bw.flush();
        } catch (Exception e) {

            logger.error("创建mapper.xml失败！",e);
        } finally {
            if(bw != null) {
                try {
                    bw.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
            if(outw != null) {
                try {
                    outw.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
            if(out != null) {
                try {
                    out.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }

        }

    }

}
